using System;
using System.Diagnostics;
using System.IO;
using Microsoft.XmlDiffPatch;
using NUnit.Framework;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using iTextSharp.text.xml;
using List = iTextSharp.text.List;

namespace itextsharp.tests.text.pdf {
    public class TaggedPdfTest {

        private const String text = "Lorem ipsum dolor sit amet," +
                                    "consectetur adipiscing elit." +
                                    "Pellentesque a lectus sit amet lectus accumsan aliquam." +
                                    "Quisque facilisis ullamcorper dolor, quis gravida leo faucibus in. Donec a dolor ligula, quis placerat nunc. Etiam enim velit, egestas in lacinia at, ultricies eu massa." +
                                    "Cras ornare felis id quam vehicula lobortis. Ut semper malesuada nulla, in vulputate dui eleifend at. Phasellus pulvinar nisl a lorem volutpat pellentesque. In vitae" +
                                    "ligula et quam vestibulum iaculis eget vitae massa. Fusce vitae leo ut diam suscipit dictum in id sapien. Praesent mi ligula, auctor vitae ultrices in, venenatis non" +
                                    "odio. Nullam sit amet velit pellentesque lectus consectetur lacinia nec quis mi. In hac habitasse platea dictumst." +
                                    "Quisque facilisis ullamcorper dolor, quis gravida leo faucibus in." +
                                    "Donec a dolor ligula, quis placerat nunc.\n" +
                                    "1. Etiam enim velit, egestas in lacinia at, ultricies eu massa. Cras ornare felis id quam vehicula lobortis. Ut semper malesuada nulla, in vulputate dui eleifend at." +
                                    "Phasellus pulvinar nisl a lorem volutpat pellentesque. In vitae ligula et quam vestibulum iaculis eget vitae massa. Fusce vitae leo ut diam suscipit dictum in id" +
                                    "sapien. Praesent mi ligula, auctor vitae ultrices in, venenatis non odio. Nullam sit amet velit pellentesque lectus consectetur lacinia nec quis mi. In hac" +
                                    "habitasse platea dictumst.\n" +
                                    "2. Morbi euismod, nunc quis malesuada feugiat, dui nibh rhoncus leo, quis cursus erat tellus vel tortor. Mauris nibh dolor, iaculis et pharetra pretium," +
                                    "pellentesque vitae erat. Aenean enim nisi, euismod quis ultricies vel, convallis nec nulla. Suspendisse nisl purus, molestie et egestas ac, cursus in mauris." +
                                    "Aliquam erat volutpat. Donec at nulla in elit faucibus mollis ac vel enim. Nullam dapibus dui sit amet sem consectetur ac vulputate est sagittis. Aliquam luctus" +
                                    "ornare nulla. Mauris adipiscing congue pharetra. Proin tempus, nibh sed pretium tempor, arcu est hendrerit est, et dignissim odio leo non purus." +
                                    "Suspendisse non elit massa. Vestibulum tincidunt ipsum vitae dui congue sagittis. Aenean porttitor tristique euismod. Nulla id justo in quam imperdiet" +
                                    "facilisis ut non turpis. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
                                    "3. Aliquam non elit ligula, nec hendrerit urna. Mauris ut velit sapien. Sed in convallis diam. Nulla faucibus, purus a porttitor ultrices, est quam convallis magna," +
                                    "molestie aliquam sapien nulla eget metus. Integer nec enim mi, eu mattis massa. Integer quis sapien vel purus pretium ullamcorper ac id dui. Suspendisse" +
                                    "pellentesque tellus sit amet neque pulvinar egestas lacinia diam imperdiet.\n" +
                                    "4. Curabitur hendrerit, sem et facilisis vestibulum, massa felis vestibulum ligula, ut faucibus massa nisi in neque. Nulla facilisi. Etiam diam mauris, pellentesque" +
                                    "lacinia dapibus at, lobortis non quam. Nullam et neque quis diam vestibulum scelerisque ullamcorper non mauris. Cras massa enim, commodo malesuada" +
                                    "tincidunt ac, lobortis eu erat. Sed sed risus velit. Suspendisse tellus tortor, ullamcorper nec tristique ac, semper non nulla. Maecenas vitae diam orci, sed" +
                                    "fermentum enim. Curabitur a libero nisl, vel laoreet nulla. Integer id volutpat sem. Pellentesque blandit, tellus at consequat dictum, urna sem elementum nisi," +
                                    "a bibendum nisi ipsum sit amet felis. Donec mattis ipsum nec metus lobortis eget volutpat nisl volutpat.\n" +
                                    "5. Fusce in aliquet nibh. Etiam quis varius ipsum. Vivamus sit amet mauris a libero iaculis semper in a neque. Nam faucibus congue posuere. Cras vitae nibh" +
                                    "sed magna ultricies pretium. Proin eget lacus quis dui ullamcorper cursus commodo in lacus. Quisque et sem id leo venenatis dictum dignissim et felis." +
                                    "Vestibulum enim urna, vehicula vel dictum in, congue quis sapien. Quisque ac mauris tellus. Nulla cursus pellentesque mauris viverra bibendum. Fusce" +
                                    "molestie dui id sem blandit in convallis justo euismod. Curabitur velit nisi, adipiscing sed consequat et, dignissim eget dolor. Aenean malesuada quam id mi" +
                                    "vestibulum pulvinar. Nullam diam quam, lobortis sit amet semper vitae, tempus eget dolor.";

        public const String RESOURCES = @"..\..\resources\text\pdf\TaggedPdfTest\";
        public const String TARGET = "TaggedPdfTest\\";
        public const String OUT = TARGET + "pdf\\out";
        private Document document;
        private Paragraph h1;
        private string output;
        private PdfWriter writer;


        [SetUp]
        virtual public void Initialize() {
            Directory.CreateDirectory(TARGET + "pdf");
            Directory.CreateDirectory(TARGET + "xml");
            Document.Compress = false;
        }

        private void InitializeDocument(String name) {
            InitializeDocument(name, PdfWriter.VERSION_1_7);
        }

        private void InitializeDocument(String name, char pdfVersion) {
            output = OUT + name + ".pdf";
            document = new Document();
            writer = PdfWriter.GetInstance(document, new FileStream(output, FileMode.Create));
            writer.PdfVersion = pdfVersion;
            writer.SetTagged();
            document.Open();

            //Required for PDF/UA
            writer.ViewerPreferences = PdfWriter.DisplayDocTitle;
            document.AddLanguage("en-US");
            document.AddTitle("Some title");
            writer.CreateXmpMetadata();
            Chunk c = new Chunk("Document Header", new Font(Font.FontFamily.HELVETICA, 14, Font.BOLD, BaseColor.BLUE));
            h1 = new Paragraph(c);
            h1.Role = PdfName.H1;
        }

        [Test]
        virtual public void CreateTaggedPdf0() {
            InitializeDocument("0");
            Paragraph paragraph = new Paragraph();
            Chunk c = new Chunk(" Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n\n");
            paragraph.Add(c);
            ColumnText columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();
            document.Close();

            InitializeDocument("0");
            paragraph = new Paragraph();
            c = new Chunk("  ");
            paragraph.Add(c);
            columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();
            document.Close();

            InitializeDocument("0");
            paragraph = new Paragraph();
            c = new Chunk("Hello World");
            paragraph.Add(c);
            columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();
            document.Close();

            InitializeDocument("0");
            paragraph = new Paragraph();
            c = new Chunk("Hello World");
            paragraph.Add(c);
            document.Add(paragraph);
            document.Close();

            InitializeDocument("0");
            paragraph = new Paragraph();
            c = new Chunk(" Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n");
            paragraph.Add(c);
            paragraph.Font = new Font(Font.FontFamily.HELVETICA, 8, Font.NORMAL, BaseColor.RED);
            document.Add(paragraph);
            document.Close();
        }


        [Test]
        virtual public void CreateTaggedPdf1() {
            InitializeDocument("1");
            Paragraph paragraph = new Paragraph(text);
            paragraph.Font = new Font(Font.FontFamily.HELVETICA, 8, Font.NORMAL, BaseColor.RED);
            ColumnText columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(h1);
            columnText.AddElement(paragraph);
            columnText.Go();
            columnText.SetSimpleColumn(300, 36, 500, 800);
            columnText.Go();
            document.Close();
            CompareResults("1");
        }

        [Test]
        virtual public void CreateTaggedPdf2() {
            InitializeDocument("2");
            Paragraph paragraph = new Paragraph(text);
            ColumnText columnText = new ColumnText(writer.DirectContent);

            columnText.SetSimpleColumn(36, 36, 400, 800);
            columnText.AddElement(h1);
            columnText.AddElement(paragraph);
            columnText.Go();
            document.NewPage();
            columnText.SetSimpleColumn(36, 36, 400, 800);
            columnText.Go();
            document.Close();
            CompareResults("2");
        }

        [Test]
        virtual public void CreateTaggedPdf3() {
            InitializeDocument("3");
            Paragraph paragraph = new Paragraph(text);
            document.Add(h1);
            document.Add(paragraph);
            document.Close();
            CompareResults("3");
        }

        [Test]
        virtual public void CreateTaggedPdf4() {
            InitializeDocument("4");
            Paragraph p = new Paragraph();
            PdfName nParagraph = new PdfName("Paragraph");
            p.Role = nParagraph;
            writer.StructureTreeRoot.MapRole(nParagraph, PdfName.P);

            try {
                Chunk c = new Chunk("Quick brown ");
                PdfName nTextBlock = new PdfName("TextBlock");
                c.Role = nTextBlock;
                writer.StructureTreeRoot.MapRole(nTextBlock, PdfName.SPAN);
                p.Add(c);
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                c = new Chunk(i, 0, 0);
                PdfName nImage = new PdfName("Image");
                c.Role = nImage;
                writer.StructureTreeRoot.MapRole(nImage, PdfName.FIGURE);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                p.Add(c);
                p.Add(new Chunk(" jumped over a lazy "));
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                p.Add(c);
            }
            catch (Exception) {
            }
            document.Add(h1);
            document.Add(p);
            document.Close();
            CompareResults("4");
        }

        [Test]
        virtual public void CreateTaggedPdf5() {
            InitializeDocument("5");
            List list = new List(true);
            try {
                list = new List(true);
                ListItem listItem =
                    new ListItem(
                        new Chunk(
                            "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line."));
                list.Add(listItem);
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                Chunk c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Chunk("jumped over a lazy"));
                list.Add(listItem);
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                listItem = new ListItem(c);
                list.Add(listItem);
            }
            catch (Exception) {
            }
            document.Add(h1);
            document.Add(list);
            document.Close();

            CompareResults("5");
        }

        [Test]
        virtual public void CreateTaggedPdf6() {
            InitializeDocument("6");

            ColumnText columnText = new ColumnText(writer.DirectContent);

            List list = new List(true);
            try {
                list = new List(true);
                ListItem listItem =
                    new ListItem(
                        new Chunk(
                            "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line."));
                list.Add(listItem);
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                Chunk c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Chunk("jumped over a lazy"));
                list.Add(listItem);
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                listItem = new ListItem(c);
                list.Add(listItem);
            }
            catch (Exception) {
            }
            columnText.SetSimpleColumn(36, 36, 400, 800);
            columnText.AddElement(h1);
            columnText.AddElement(list);
            columnText.Go();
            document.Close();
            CompareResults("6");
        }

        [Test]
        virtual public void CreateTaggedPdf7() {
            InitializeDocument("7");
            List list = new List(true);
            try {
                list = new List(true);
                ListItem listItem =
                    new ListItem(
                        new Chunk(
                            "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line."));
                list.Add(listItem);
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                Chunk c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Chunk("jumped over a lazy"));
                list.Add(listItem);
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Paragraph(text));
                list.Add(listItem);
            }
            catch (Exception) {
            }
            document.Add(h1);
            document.Add(list);
            document.Close();

            CompareResults("7");
        }

        [Test]
        virtual public void CreateTaggedPdf8() {
            InitializeDocument("8");

            ColumnText columnText = new ColumnText(writer.DirectContent);

            List list = new List(true);
            try {
                list = new List(true);
                ListItem listItem =
                    new ListItem(
                        new Chunk(
                            "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line."));
                list.Add(listItem);
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                Chunk c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Chunk("jumped over a lazy"));
                list.Add(listItem);
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                listItem = new ListItem(c);
                list.Add(listItem);
                listItem = new ListItem(new Paragraph(text));
                list.Add(listItem);
            }
            catch (Exception) {
            }
            columnText.SetSimpleColumn(36, 36, 400, 800);
            columnText.AddElement(h1);
            columnText.AddElement(list);
            columnText.Go();
            document.NewPage();
            columnText.SetSimpleColumn(36, 36, 400, 800);
            columnText.Go();
            document.Close();

            CompareResults("8");
        }

        [Test]
        virtual public void CreateTaggedPdf9() {
            InitializeDocument("9");
            PdfPTable table = new PdfPTable(2);
            try {
                table.AddCell(
                    "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line.");
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                table.AddCell(i);
                table.AddCell("jumped over a lazy");
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                table.AddCell(i);
                table.AddCell("Hello World");
                Paragraph p = new Paragraph(text);
                table.AddCell(p);
            }
            catch (Exception) {
            }
            document.Add(h1);
            document.Add(table);
            document.Add(
                new Paragraph(
                    "Extra paragraph at the end of the document. Please make sure that this is really last portion of page content."));
            document.Close();
            CompareResults("9");
        }

        [Test]
        virtual public void CreateTaggedPdf10() {
            InitializeDocument("10");
            PdfPTable table = new PdfPTable(2);
            try {
                table.AddCell(
                    "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line.");
                Image i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                table.AddCell(i);
                table.AddCell("jumped over a lazy");
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                table.AddCell(i);

                PdfPTable t = new PdfPTable(2);
                t.AddCell(
                    "Quick brown fox jumped over a lazy dog. A very long line appears here because we need new line.");
                i = Image.GetInstance(RESOURCES + "img\\fox.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                t.AddCell(i);
                t.AddCell("jumped over a lazy");
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                i.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                t.AddCell(i);
                t.AddCell(text);
                t.AddCell("Hello World");
                table.AddCell(t);


                Paragraph p = new Paragraph(text);
                table.AddCell(p);
            }
            catch (Exception) {
            }
            document.Add(h1);
            document.Add(table);
            document.Close();

            CompareResults("10");
        }

        [Test]
        virtual public void CreateTaggedPdf11() {
            InitializeDocument("11");

            Chapter c =
                new Chapter(
                    new Paragraph("First chapter", new Font(Font.FontFamily.HELVETICA, 16, Font.BOLD, BaseColor.BLUE)),
                    1);
            c.TriggerNewPage = false;
            c.Indentation = 40;
            Section s1 =
                c.AddSection(new Paragraph("First section of a first chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            Section s2 =
                s1.AddSection(new Paragraph("First subsection of a first section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a first section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a first section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Second section of a first chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a second section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a second section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a second section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Third section of a first chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a third section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a third section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a third section of a first chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            document.Add(c);

            c =
                new Chapter(
                    new Paragraph("Second chapter", new Font(Font.FontFamily.HELVETICA, 16, Font.BOLD, BaseColor.BLUE)),
                    2);
            c.TriggerNewPage = false;
            c.Indentation = 40;
            s1 =
                c.AddSection(new Paragraph("First section of a second chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a first section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a first section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a first section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Second section of a second chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a second section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a second section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a second section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Third section of a second chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a third section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a third section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a third section of a second chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            document.Add(c);

            c =
                new Chapter(
                    new Paragraph("Third chapter", new Font(Font.FontFamily.HELVETICA, 16, Font.BOLD, BaseColor.BLUE)),
                    3);
            c.TriggerNewPage = false;
            c.Indentation = 40;
            s1 =
                c.AddSection(new Paragraph("First section of a third chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a first section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a first section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a first section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Second section of a third chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a second section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a second section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a second section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s1 =
                c.AddSection(new Paragraph("Third section of a third chapter",
                                           new Font(Font.FontFamily.HELVETICA, 13, Font.BOLD, BaseColor.BLUE)));
            s1.Indentation = 20;
            s2 =
                s1.AddSection(new Paragraph("First subsection of a third section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Second subsection of a third section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            s2 =
                s1.AddSection(new Paragraph("Third subsection of a third section of a third chapter",
                                            new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE)));
            s2.Indentation = 10;
            s2.Add(new Paragraph("Some text..."));
            document.Add(c);

            c = new Chapter(4);
            c.TriggerNewPage = false;
            c.Indentation = 40;
            c.AddSection("First section of a fourths chapter, the chapter itself is invisible");
            document.Add(c);

            document.Close();

            CompareResults("11");
        }

        [Test]
        virtual public void CreateTaggedPdf12() {
            InitializeDocument("12");

            PdfPTable table = new PdfPTable(2);
            PdfPCell cell = new PdfPCell(new Paragraph("header 1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("header 2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            table.HeaderRows = 4;
            table.FooterRows = 2;
            try {
                for (int i = 1; i <= 50; i++) {
                    table.AddCell("row " + i + ", column 1");
                    table.AddCell("row " + i + ", column 2");
                }
            }
            catch (Exception) {
            }
            document.Add(table);
            document.Close();

            CompareResults("12");
        }

        [Test]
        virtual public void CreateTaggedPdf13() {
            InitializeDocument("13");

            Paragraph p = new Paragraph();
            Chunk chunk = new Chunk("Please visit ");
            p.Add(chunk);

            PdfAction action = new PdfAction("http://itextpdf.com");
            chunk = new Chunk("http://itextpdf.com",
                              new Font(Font.FontFamily.HELVETICA, Font.UNDEFINED, Font.UNDERLINE, BaseColor.BLUE));
            chunk.SetAction(action);
            p.Add(chunk);
            p.Add(new Chunk(" for more details."));
            document.Add(p);
            document.Close();
            CompareResults("13");
        }

        [Test]
        virtual public void CreateTaggedPdf14() {
            InitializeDocument("14");
            Paragraph paragraph = new Paragraph("Document MUST contain 1 page only!");
            document.NewPage();
            ColumnText columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();
            document.Close();

            PdfReader reader = new PdfReader(OUT + "14.pdf");
            Assert.AreEqual(1, reader.NumberOfPages);
        }

        [Test]
        virtual public void CreateTaggedPdf15() {
            InitializeDocument("15");

            Paragraph p = new Paragraph();
            Chunk chunk = new Chunk("Hello tagged world!");
            chunk.SetBackground(new BaseColor(255, 0, 255));
            chunk.Font = FontFactory.GetFont("TimesNewRoman", 20, BaseColor.ORANGE);
            chunk.SetUnderline(BaseColor.PINK, 1.2f, 1, 1, 1, 0);
            p.Add(chunk);

            document.Add(p);
            document.Close();
            CompareResults("15");
        }

        [Test]
        virtual public void CreateTaggedPdf16() {
            InitializeDocument("16");

            Paragraph p = new Paragraph();
            Chunk chunk = new Chunk("Hello tagged world!");
            chunk.SetBackground(new BaseColor(255, 0, 255));
            chunk.Font = FontFactory.GetFont("TimesNewRoman", 20, BaseColor.ORANGE);
            chunk.SetUnderline(BaseColor.PINK, 1.2f, 1, 1, 1, 0);
            p.Add(chunk);
            PdfDiv div = new PdfDiv();
            div.AddElement(p);
            document.Add(div);

            document.Add(new Paragraph("This paragraph appears between 2 div blocks"));

            div = new PdfDiv();
            div.AddElement(new Paragraph(text));
            document.Add(div);


            document.Close();
            CompareResults("16");
        }

        [Test]
        virtual public void CreateTaggedPdf17() {
            InitializeDocument("17");

            PdfPTable table = new PdfPTable(2);
            PdfPCell cell = new PdfPCell(new Paragraph("h1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("h2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            table.HeaderRows = 4;
            table.FooterRows = 2;

            try {
                PdfPHeaderCell headerCell = new PdfPHeaderCell();
                headerCell.Scope = PdfPHeaderCell.ROW;
                headerCell.Phrase = new Phrase("header1");
                headerCell.Name = "header1";
                table.AddCell(headerCell);
                PdfPHeaderCell headerCell2 = new PdfPHeaderCell();
                headerCell2.Scope = PdfPHeaderCell.ROW;
                headerCell2.Phrase = new Phrase("header2");
                headerCell2.Name = "header2";
                table.AddCell(headerCell2);
                cell = new PdfPCell(new Phrase("row 2, column 1"));
                cell.AddHeader(headerCell);
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase("row 2, column 2"));
                cell.AddHeader(headerCell2);
                cell.AddHeader(headerCell2);
                table.AddCell(cell);
            }
            catch (Exception e) {
                Trace.WriteLine(e.Message);
            }
            document.Add(table);
            document.Close();
            CompareResults("17");
        }

        [Test]
        virtual public void CreateTaggedPdf18() {
            InitializeDocument("18");

            PdfDiv div = new PdfDiv();

            Paragraph paragraph = new Paragraph(text);
            paragraph.Font = new Font(Font.FontFamily.HELVETICA, 8, Font.NORMAL, BaseColor.RED);

            div.BackgroundColor = BaseColor.MAGENTA;
            div.TextAlignment = Element.ALIGN_CENTER;
            div.AddElement(paragraph);
            document.Add(div);
            document.Close();
            CompareResults("18");
        }


        [Test]
        virtual public void CreateTaggedPdf19() {
            InitializeDocument("19");

            PdfDiv div = new PdfDiv();
            writer.DirectContent.OpenMCBlock(div);

            PdfArtifact artifact = new PdfArtifact();
            artifact.Type = new PdfString("Background");
            writer.DirectContent.OpenMCBlock(artifact);
            writer.DirectContent.SetColorFill(BaseColor.RED);
            writer.DirectContent.Rectangle(100, 100, 400, 400);
            writer.DirectContent.Fill();
            writer.DirectContent.CloseMCBlock(artifact);

            writer.DirectContent.CloseMCBlock(div);

            document.Close();
            CompareResults("19");
        }

        [Test]
        virtual public void CreateTaggedPdf20() {
            InitializeDocument("20");

            Paragraph paragraph = new Paragraph();
            paragraph.Font.Color = BaseColor.RED;
            Chunk c = new Chunk("Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n\n");
            paragraph.Add(c);

            ColumnText columnText = new ColumnText(writer.DirectContent);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();

            PdfTemplate template = writer.DirectContent.CreateTemplate(PageSize.A4.Width, PageSize.A4.Height);
            writer.DirectContent.AddTemplate(template, 0, 0, true);

            columnText = new ColumnText(template);
            columnText.SetSimpleColumn(36, 36, 250, 750);
            columnText.AddText(new Phrase(new Chunk("Hello word \n")));
            columnText.Go();

            document.NewPage();

            paragraph = new Paragraph();
            paragraph.Font.Color = BaseColor.RED;
            c = new Chunk("Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n");
            paragraph.Add(c);

            columnText = new ColumnText(template);
            columnText.SetSimpleColumn(36, 36, 250, 700);
            columnText.AddElement(paragraph);
            columnText.Go();

            template = writer.DirectContent.CreateTemplate(PageSize.A4.Width, PageSize.A4.Height);
            writer.DirectContent.AddTemplate(template, 0, 0, true);

            paragraph = new Paragraph();
            paragraph.Font.Color = BaseColor.GREEN;
            c = new Chunk("Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n");
            paragraph.Add(c);

            columnText = new ColumnText(template);
            columnText.SetSimpleColumn(36, 36, 250, 800);
            columnText.AddElement(paragraph);
            columnText.Go();

            paragraph = new Paragraph();
            paragraph.Font.Color = BaseColor.BLUE;
            c = new Chunk("Hello ");
            paragraph.Add(c);
            c = new Chunk("  world\n");
            paragraph.Add(c);

            template = writer.DirectContent.CreateTemplate(PageSize.A4.Width, PageSize.A4.Height);

            columnText = new ColumnText(template);
            columnText.SetSimpleColumn(36, 36, 250, 650);
            columnText.AddElement(paragraph);
            columnText.Go();

            writer.DirectContent.AddTemplate(template, 0, 100);

            writer.DirectContent.AddTemplate(template, 0, 50);

            writer.DirectContent.AddTemplate(template, 0, 0);

            document.Close();
            CompareResults("20");
        }

        [Test]
        virtual public void CreateTaggedPdf21() {
            try {
                InitializeDocument("21");

                PdfTemplate template = writer.DirectContent.CreateTemplate(PageSize.A4.Width, PageSize.A4.Height);

                writer.DirectContent.AddTemplate(template, 0, 0, true);

                ColumnText columnText = new ColumnText(template);
                columnText.SetSimpleColumn(36, 36, 250, 750);
                columnText.AddText(new Phrase("Hello word \n\n"));
                columnText.Go();

                document.NewPage();
                writer.DirectContent.AddTemplate(template, 0, 0);

                document.Close();
            }
            catch (Exception conformExc) {
                Assert.AreEqual("Template with tagged content could not be used more than once.", conformExc.Message);
                return;
            }
            finally {
                document.Close();
            }
            Assert.Fail("Expected error: 'Template with tagged content could not be used more than once.");
        }

        [Test]
        virtual public void CreateTaggedPdf22() {
            InitializeDocument("22", PdfWriter.VERSION_1_4);
            Paragraph p = new Paragraph();
            PdfName nParagraph = new PdfName("Paragraph");
            p.Role = nParagraph;
            writer.StructureTreeRoot.MapRole(nParagraph, PdfName.P);

            try {
                Chunk c = new Chunk("Quick brown ");
                PdfName nTextBlock = new PdfName("TextBlock");
                c.Role = nTextBlock;
                writer.StructureTreeRoot.MapRole(nTextBlock, PdfName.SPAN);
                p.Add(c);
                Image i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                PdfName nImage = new PdfName("Image");
                c.Role = nImage;
                writer.StructureTreeRoot.MapRole(nImage, PdfName.FIGURE);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Fox image"));
                p.Add(c);
                p.Add(new Chunk(" jumped over a lazy "));
                i = Image.GetInstance(RESOURCES + "img\\dog.bmp");
                c = new Chunk(i, 0, 0);
                c.SetAccessibleAttribute(PdfName.ALT, new PdfString("Dog image"));
                p.Add(c);
            }
            catch (Exception e) {
            }
            document.Add(h1);
            document.Add(p);
            document.Close();
            CompareResults("22");
        }

        [Test]
        virtual public void CreateTaggedPdf23() {
            InitializeDocument("23", PdfWriter.VERSION_1_4);

            PdfPTable table = new PdfPTable(2);
            PdfPCell cell = new PdfPCell(new Paragraph("header 1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("header 2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 1"));
            cell.Colspan = 2;
            table.AddCell(cell);
            cell = new PdfPCell(new Paragraph("footer 2"));
            cell.Colspan = 2;
            table.AddCell(cell);
            table.HeaderRows = 4;
            table.FooterRows = 2;
            try {
                for (int i = 1; i <= 50; i++) {
                    table.AddCell("row " + i + ", column 1");
                    table.AddCell("row " + i + ", column 2");
                }
            }
            catch (Exception e) {
            }
            document.Add(table);
            document.Close();

            CompareResults("23");
        }

        [Test]
        public virtual void CreateTaggedPdf24() {
            Document document = new Document(PageSize.LETTER);

            MemoryStream baos = new MemoryStream();

            PdfWriter writer = PdfWriter.GetInstance(document, baos);

            writer.ViewerPreferences = PdfWriter.DisplayDocTitle;

//set more document properties

            writer.PdfVersion = PdfWriter.VERSION_1_7;
            writer.SetTagged(PdfWriter.markInlineElementsOnly);
            PdfDictionary info = writer.Info;
            info.Put(PdfName.TITLE, new PdfString("Testing"));

            writer.CreateXmpMetadata();


// step 3

            document.Open();
            document.AddLanguage("en_US");
            document.SetAccessibleAttribute(PdfName.LANG, new PdfString("en_US"));

// step 4

            Paragraph p = new Paragraph("Paragraph testing testing");
            p.SetAccessibleAttribute(PdfName.ACTUALTEXT, new PdfString("Paragraph ALT Text"));
            p.SetAccessibleAttribute(PdfName.ALT, new PdfString("Paragraph ALT Text"));
            document.Add(p);


            Chunk ck = new Chunk("Span testing testing", FontFactory.GetFont(RESOURCES + @"..\FreeMonoBold.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED, 12));
            ck.SetAccessibleAttribute(PdfName.ACTUALTEXT, new PdfString("Span ALT Text"));
            ck.SetAccessibleAttribute(PdfName.ALT, new PdfString("Span ALT Text"));
            p = new Paragraph(ck);

            document.Add(p);

// step 5
            document.Close();

            FileStream fos = new FileStream("TaggedPdfTest/pdf/out24.pdf", FileMode.Create);

            byte[] buff = baos.ToArray();
            fos.Write(buff, 0, buff.Length);

            fos.Flush();

            fos.Close();
            CompareResults("24");
        }

        [TearDown]
        virtual public void Compress() {
            Document.Compress = true;
        }

        private void CompareResults(String name) {
            PdfReader reader = new PdfReader(OUT + name + ".pdf");
            string orig = RESOURCES + "xml\\test" + name + ".xml";
            string curr = TARGET + "xml\\test" + name + ".xml";
            FileStream xmlOut = new FileStream(curr, FileMode.Create);
            new MyTaggedPdfReaderTool().ConvertToXml(reader, xmlOut);
            xmlOut.Close();
            XmlDiff xmldiff = new XmlDiff(XmlDiffOptions.None);
            Assert.True(xmldiff.Compare(orig, curr, false));
        }

        #region Nested type: MyMarkedContentRenderFilter

        private class MyMarkedContentRenderFilter : MarkedContentRenderFilter {
            private readonly int mcid;

            public MyMarkedContentRenderFilter(int mcid)
                : base(mcid) {
                this.mcid = mcid;
            }

            public override bool AllowText(TextRenderInfo renderInfo) {
                return renderInfo.HasMcid(mcid, true);
            }
        }

        #endregion

        #region Nested type: MyTaggedPdfReaderTool

        private class MyTaggedPdfReaderTool : TaggedPdfReaderTool {
            public override void ParseTag(String tag, PdfObject obj, PdfDictionary page) {
                if (obj is PdfNumber) {
                    PdfNumber mcid = (PdfNumber) obj;
                    RenderFilter filter = new MyMarkedContentRenderFilter(mcid.IntValue);
                    ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
                    FilteredTextRenderListener listener = new FilteredTextRenderListener(
                        strategy, filter);
                    PdfContentStreamProcessor processor = new PdfContentStreamProcessor(
                        listener);
                    processor.ProcessContent(PdfReader.GetPageContent(page), page
                                                                                 .GetAsDict(PdfName.RESOURCES));
                    outp.Write(XMLUtil.EscapeXML(listener.GetResultantText(), true));
                }
                else {
                    base.ParseTag(tag, obj, page);
                }
            }

            public override void InspectChildDictionary(PdfDictionary k) {
                InspectChildDictionary(k, true);
            }
        }

        #endregion
    }
}
